package com.sukaiyi.giteejavaapi.converts;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONObject;
import com.sukaiyi.giteejavaapi.common.HttpEndpoint;
import com.sukaiyi.giteejavaapi.http.model.HttpRequest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author sukaiyi
 * @date 2020/07/22
 */
public class HttpEndpointToRequestConverter implements Converter<HttpEndpoint, HttpRequest> {

    private final Object param;
    private final Map<String, String> env;

    public HttpEndpointToRequestConverter(Object param, Map<String, String> env) {
        this.param = param;
        this.env = env;
    }

    @Override
    public HttpRequest exec(HttpEndpoint endpoint) {
        String method = endpoint.getMethod().name();
        String url = Optional.of(endpoint).map(HttpEndpoint::getUrl).map(e -> handleParam(e, param)).orElse("");
        Map<String, String> headers = new HashMap<>();
        if (endpoint.getHeaders() != null) {
            for (Map.Entry<String, String> entry : endpoint.getHeaders().entrySet()) {
                String value;
                if ((value = handleParam(entry.getValue(), param)) != null) {
                    headers.put(entry.getKey(), value);
                }
            }
        }
        JSONObject requestBody = null;
        List<HttpEndpoint.Param> params = endpoint.getParams();
        for (HttpEndpoint.Param p : params) {
            if (p.getType() == HttpEndpoint.ParamType.QUERY) {
                Object value = getParam(p.getName(), param);
                if (value != null) {
                    String separator = url.contains("?") ? "&" : "?";
                    url = url + separator + p.getName() + "=" + value;
                }
            } else if (p.getType() == HttpEndpoint.ParamType.FORMDATA) {
                Object value = getParam(p.getName(), param);
                if (value != null) {
                    if (requestBody == null) {
                        requestBody = new JSONObject();
                    }
                    requestBody.put(p.getName(), value);
                }
            } else if (p.getType() == HttpEndpoint.ParamType.BODY) {
                Object value = getParam(p.getName(), param);
                if (value != null) {
                    if (requestBody == null) {
                        requestBody = new JSONObject();
                    }
                    requestBody.put(p.getName(), value);
                }
            }
        }
        return new HttpRequest(
                method, url, headers, requestBody == null ? null : requestBody.toString()
        );
    }

    private String handleParam(String raw, Object param) {
        int leftMark = 0;
        int rightMark = 0;
        while (true) {
            leftMark = raw.indexOf("{{");
            rightMark = raw.indexOf("}}");
            if (leftMark == -1 || rightMark == -1 || leftMark >= rightMark) {
                break;
            }
            String paramMarkWithBrackets = raw.substring(leftMark, rightMark + 2);
            String paramMark = paramMarkWithBrackets.substring(2, paramMarkWithBrackets.length() - 2);
            Object paramValue = getParam(paramMark, param);
            raw = raw.replace(paramMarkWithBrackets, Optional.ofNullable(paramValue).map(Convert::toStr).orElse(""));
        }
        return raw;
    }

    @SuppressWarnings("all")
    private Object getParam(String name, Object param) {
        Object paramFromObj = null;
        if (param instanceof Map) {
            paramFromObj = ((Map) param).get(name);
        } else {
            paramFromObj = ReflectUtil.getFieldValue(param, name);
        }
        if (paramFromObj != null) {
            return paramFromObj;
        }
        return env.get(name);
    }
}
